import * as vscode from 'vscode';
import { Memory } from './memory';
export enum DataType {
  user = 'user',
  space = 'space',
  project = 'project',
  module = 'module',
  folder = 'folder',
  api = 'api',
  empty = 'empty',
}
interface DataMap {
  [DataType.user]: string;
  [DataType.space]: Memory.ISpace;
  [DataType.project]: Memory.IProject;
  [DataType.module]: Memory.IModule;
  [DataType.folder]: Memory.IDoc;
  [DataType.api]: Memory.IDoc;
  [DataType.empty]: string;
}

export class TreeData<K extends keyof DataMap = keyof DataMap> extends vscode.TreeItem {
  readonly type: K;
  readonly data: DataMap[K];
  readonly userKey: string;
  constructor(type: K, userKey: string, data: DataMap[K], collapsibleState = vscode.TreeItemCollapsibleState.Collapsed) {
    let name = '';
    switch (type) {
      case DataType.user: {
        name = userKey;
        break;
      }
      case DataType.space: {
        const item = data as Memory.ISpace;
        name = `[S]${item.name} (${item.id})`;
        break;
      }
      case DataType.project: {
        const item = data as Memory.IProject;
        name = `[P]${item.name} (${item.id})`;
        break;
      }
      case DataType.module: {
        const item = data as Memory.IModule;
        name = `[M]${item.name} (${item.id})`;
        break;
      }
      case DataType.folder: {
        const item = data as Memory.IModule;
        name = `[F]${item.name} (${item.id})`;
        break;
      }
      case DataType.api: {
        const item = data as Memory.IDoc;
        const method = item.httpMethod?.toLowerCase() || 'unknown';
        name = `[A]<${method}>${item.name} ${item.url}`;
        collapsibleState = vscode.TreeItemCollapsibleState.None;
        break;
      }
      case DataType.empty: {
        name = data as string;
        collapsibleState = vscode.TreeItemCollapsibleState.None;
      }
    }
    super(name, collapsibleState);
    this.contextValue = type;
    this.userKey = userKey;
    this.type = type;
    this.data = data;

    switch (type) {
      case DataType.api: {
        this.command = {
          title: 'open',
          command: 'torna-api-visitor.viewApi',
          arguments: [this]
        };
        break;
      }
    }
  }
}
export class ApiTreeDataProvider implements vscode.TreeDataProvider<TreeData> {
  private _onDidChangeTreeData: vscode.EventEmitter<TreeData | undefined | null | void> = new vscode.EventEmitter<TreeData | undefined | null | void>();
  readonly onDidChangeTreeData: vscode.Event<TreeData | undefined | null | void> = this._onDidChangeTreeData.event;

  refresh(): void {
    this._onDidChangeTreeData.fire();
  }
  getTreeItem(element: TreeData): vscode.TreeItem | Thenable<vscode.TreeItem> {
    return element;
  }
  getChildren(element?: TreeData | undefined): vscode.ProviderResult<TreeData[]> {
    switch (element?.type) {
      case void 0: {
        const keys = Array.from(Memory.spaceLists.keys());
        return keys.length ? keys.map(key => new TreeData(DataType.user, key, key)) :
          [new TreeData(DataType.empty, '', 'api space list got empty')];
      }
      case DataType.user: {
        const ele = element as TreeData<DataType.user>;
        const id = ele.data;
        const arr = Memory.spaceLists.get(id);
        return arr?.map(item => new TreeData(DataType.space, ele.userKey, item));
      }
      case DataType.space: {
        const ele = element as TreeData<DataType.space>;
        const arr = Memory.projectLists.get(ele.userKey);
        return arr?.filter(
          item => item.spaceId === ele.data.id
        ).map(
          item => new TreeData(DataType.project, ele.userKey, item)
        );
      }
      case DataType.project: {
        const ele = element as TreeData<DataType.project>;
        const arr = Memory.moduleLists.get(ele.userKey);
        return arr?.filter(
          item => item.projectId === ele.data.id
        ).map(
          item => new TreeData(DataType.module, ele.userKey, item)
        );
      }
      case DataType.module: {
        const ele = element as TreeData<DataType.module>;
        const arr = Memory.docLists.get(ele.userKey);
        return arr?.filter(
          item => item.moduleId === ele.data.id && !item.parentId
        ).map(
          item => new TreeData(item.isFolder === 1 ? DataType.folder : DataType.api, ele.userKey, item)
        );
      }
      case DataType.folder: {
        const ele = element as TreeData<DataType.folder>;
        const arr = Memory.docLists.get(ele.userKey);
        return arr?.filter(
          item => item.parentId === ele.data.id
        ).map(
          item => new TreeData(item.isFolder === 1 ? DataType.folder : DataType.api, ele.userKey, item)
        );
      }
      case DataType.empty: {
        return void 0;
      }
    }
  }
  getParent(element: TreeData): vscode.ProviderResult<TreeData> {
    switch (element.type) {
      case DataType.user:
        return void 0;
      case DataType.space:
        return new TreeData(DataType.user, element.userKey, element.userKey);
      case DataType.project: {
        const ele = element as TreeData<DataType.project>;
        const parent = Memory.spaceLists.get(element.userKey)?.find(v => v.id === ele.data.spaceId);
        return parent ? new TreeData(DataType.space, element.userKey, parent) : void 0;
      }
      case DataType.module: {
        const ele = element as TreeData<DataType.module>;
        const parent = Memory.projectLists.get(element.userKey)?.find(v => v.id === ele.data.projectId);
        return parent ? new TreeData(DataType.project, element.userKey, parent) : void 0;
      }
      case DataType.folder: {
        const ele = element as TreeData<DataType.folder>;
        if (ele.data.parentId) {
          const parent = Memory.docLists.get(element.userKey)?.find(v => v.id === ele.data.parentId);
          return parent ? new TreeData(DataType.folder, element.userKey, parent) : void 0;
        } else {
          const parent = Memory.moduleLists.get(element.userKey)?.find(v => v.id === ele.data.moduleId);
          return parent ? new TreeData(DataType.module, element.userKey, parent) : void 0;
        }
      }
      case DataType.api: {
        const ele = element as TreeData<DataType.api>;
        if (ele.data.parentId) {
          const parent = Memory.docLists.get(element.userKey)?.find(v => v.id === ele.data.parentId);
          return parent ? new TreeData(DataType.folder, element.userKey, parent) : void 0;
        } else {
          const parent = Memory.moduleLists.get(element.userKey)?.find(v => v.id === ele.data.moduleId);
          return parent ? new TreeData(DataType.module, element.userKey, parent) : void 0;
        }
      }
      case DataType.empty:
        return void 0;
    }
  }
}
export const apiTreeDataProvider = new ApiTreeDataProvider();